#include "stm32f10x.h"
#include "stm32f10x_rcc.h"
#include "stm32f10x_gpio.h"
#include "stm32f10x_tim.h"
#include "misc.h"

#include "stdio.h"

#include "common.h"
#include "timer.h"

//TIM3 通道2 PB5
void tim_pwm_init(void)
{
	GPIO_InitTypeDef pwm_ch;
	TIM_OCInitTypeDef pwm;

	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO, ENABLE);

	//给GPIO初始化结构体赋值
	pwm_ch.GPIO_Pin = GPIO_Pin_5;
	pwm_ch.GPIO_Mode = GPIO_Mode_AF_PP;
	pwm_ch.GPIO_Speed = GPIO_Speed_50MHz;
	//初始化
	GPIO_Init(GPIOB, &pwm_ch);

	GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3, ENABLE);

	pwm.TIM_OCMode = TIM_OCMode_PWM2;
	pwm.TIM_OCPolarity = TIM_OCPolarity_High;
	pwm.TIM_OutputState = TIM_OutputState_Enable;

	TIM_OC2Init(TIM3, &pwm);

	TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Enable);
}

void tim_nvic(u8 source, u8 sub, u8 pre)
{
	NVIC_InitTypeDef tim_nvic;

	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	tim_nvic.NVIC_IRQChannel = source;
	tim_nvic.NVIC_IRQChannelSubPriority = sub;
	tim_nvic.NVIC_IRQChannelPreemptionPriority = pre;
	tim_nvic.NVIC_IRQChannelCmd = ENABLE;

	NVIC_Init(&tim_nvic);
}
//TIM3 通道1
void tim_cap_init(void)
{
	// IC：Input Capture
	TIM_ICInitTypeDef tim_cap;

	// 指定（timer3）通道1
	tim_cap.TIM_Channel = TIM_Channel_1;
	// 无滤波，按键不需要滤波，则使用的fDTS的频率
	// 即频率使用的是在tim_init里面配置的TIM_ClockDivision
	tim_cap.TIM_ICFilter = 0;
	// （极性是）上升沿触发
	// 因为（初始化是）低电平到高电平，所以这里捕获的是上升沿
	tim_cap.TIM_ICPolarity = TIM_ICPolarity_Rising;
	// 选择入口/映射方式，这里选择的入口是直接触发中断，1对应IC1，2对应IC2... ...
	tim_cap.TIM_ICSelection = TIM_ICSelection_DirectTI;
	// 预分频倍数，即指定事件（上升沿发生）发生几次算做有效电平状态
	tim_cap.TIM_ICPrescaler = TIM_ICPSC_DIV1;

	TIM_ICInit(TIM3, &tim_cap);
}
/*
tim2:1us
(PSC+1)*(ARR+1)/CLK = 1us  1ms   1s
(PSC+1)*(ARR+1) = 1 * 36000    1*36000000   
72000000   2000  36000
1000    36000
999     35999
PSC=1
2*(ARR+1)=36  ARR = 17

*(ARR+1) = 72000000
72000000-1 = 71900000
1        71

*/
void tim_init(TIM_NAME tim, MODE mode, TIM_OPR opr, u16 arr, u16 psc)
{
	TIM_TimeBaseInitTypeDef timx;

	timx.TIM_Period = arr;					   //自动装载值 0-2^16-1  //设置在下一个更新事件装入活动的自动重装载寄存器周期的值
	timx.TIM_Prescaler = psc;				   //分频系数  //设置用来作为TIMx时钟频率除数的预分频值
	timx.TIM_ClockDivision = TIM_CKD_DIV1;	   //采样频率 //设置时钟分割:TDTS = Tck_tim
	timx.TIM_CounterMode = TIM_CounterMode_Up; //向上计数

	switch (tim)
	{
	case TIMER2:
		RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
		TIM_TimeBaseInit(TIM2, &timx);
		TIM_Cmd(TIM2, ENABLE);

		if (INTERRUPT == mode)
		{
			TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);
			tim_nvic(TIM2_IRQn, 1, 0);
			TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
		}
		break;
	case TIMER3:
		RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
		TIM_TimeBaseInit(TIM3, &timx);
		TIM_Cmd(TIM3, ENABLE);

		switch (opr)
		{
		case PWM:
			tim_pwm_init();
			if (INTERRUPT == mode)
			{
			}
			break;
		case CAP:
			tim_cap_init();
			if (INTERRUPT == mode)
			{
				TIM_ITConfig(TIM3, TIM_IT_Update | TIM_IT_CC1, ENABLE);
				tim_nvic(TIM3_IRQn, 1, 1);
				TIM_ClearITPendingBit(TIM3, TIM_IT_Update | TIM_IT_CC1);
			}
			break;
		default:

			break;
		}

		break;

	default:
		break;
	}
}

void TIM2_IRQHandler(void)
{
	static u32 tim2_count = 0;

	if (SET == TIM_GetITStatus(TIM2, TIM_IT_Update))
	{
		TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
		tim2_count++;
		//if(1000000 == tim2_count)
		{
			printf("TIM2 Update\r\n");
		}
	}
}

u8 tim3_cap_flag = 0;	   //记录捕获的状态  1: 捕获到上升沿  2:捕获到下降沿
u32 tim3_cap_value = 0;	   //记录按键松开后的cnt中的值
u32 tim3_update_count = 0; //记录定时器2溢出次数

void TIM3_IRQHandler(void)
{
	if (SET == TIM_GetITStatus(TIM3, TIM_IT_Update))
	{
		TIM_ClearITPendingBit(TIM3, TIM_IT_Update);
		// 这个printf只是用来验证TIMER3是被响应的，一旦验证了就可以注释掉
		// 我们真正关心的还是CC1的触发
		// printf("TIM3 Update\r\n");

		// 如果按键的时间过长，长度长于arr的装载值的时长，发生了异常，就又从0开始计时
		// TIM_GetCapture1返回值不再是完整的值了；所以需要按键过程中溢出的次数进行记录

		// 这个分支说明：如果还是在上升沿的状态，即按下状态，每次走到这个中断就需要计数
		if (1 == tim3_cap_flag)
		{
			tim3_update_count++;
			//bug: tim3_update_count的取值范围是u32，如果下按事件过长，可能会有溢出情况
		}
	}
	if (SET == TIM_GetITStatus(TIM3, TIM_IT_CC1))
	{
		TIM_ClearITPendingBit(TIM3, TIM_IT_CC1);

		printf("TIM3 CC1\r\n");
		// 如果上一次是探测到上升沿
		if (1 == tim3_cap_flag)
		{
			// 这一次函数的触发，说明是探测到了下降沿，设置flag值位2
			tim3_cap_flag = 2;
			// 获取上一次的时间戳
			tim3_cap_value = TIM_GetCapture1(TIM3);
			// 改变极性位
			TIM_OC1PolarityConfig(TIM3, TIM_ICPolarity_Rising);
			printf("Rising\r\n");
		}
		// 初始化状态，或者上一次是探测下降沿
		else
		{
			// 所以走到这里说明捕获到了上升沿，设置当前状态位捕获到了上升沿
			tim3_cap_flag = 1;
			// 改变极性位
			TIM_OC1PolarityConfig(TIM3, TIM_ICPolarity_Falling);
			printf("Falling\r\n");
		}
	}
}
